package com.corpgovernment.travelstandard.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.corpgovernment.api.applytrip.apply.sync.StandardReserveTypeSyncRequest;
import com.corpgovernment.api.applytrip.soa.response.QueryApplyTripStandardResponse;
import com.corpgovernment.api.flightintl.dto.enums.CabinFlag;
import com.corpgovernment.api.organization.model.post.PostVo;
import com.corpgovernment.api.travelstandard.enums.ClazzEnum;
import com.corpgovernment.api.travelstandard.enums.ControlTypeEnum;
import com.corpgovernment.api.travelstandard.enums.FlightSwitchEnum;
import com.corpgovernment.api.travelstandard.enums.FlightSwitchEnum.RcEnum;
import com.corpgovernment.api.travelstandard.enums.ReasonCodeTypeEnum;
import com.corpgovernment.api.travelstandard.enums.TravelStandardTypeEnum;
import com.corpgovernment.api.travelstandard.service.IMbTravelstandFlightService;
import com.corpgovernment.api.travelstandard.vo.AdvancedBook;
import com.corpgovernment.api.travelstandard.vo.ClassDiscountControl;
import com.corpgovernment.api.travelstandard.vo.ClassSpace;
import com.corpgovernment.api.travelstandard.vo.FlightAmountControlVo;
import com.corpgovernment.api.travelstandard.vo.FlightTravelStandardManageVo;
import com.corpgovernment.api.travelstandard.vo.FlightTravelStandardShowVo;
import com.corpgovernment.api.travelstandard.vo.FlightTravelStandardShowVo.PolicyRuleVo.PolicyDetail;
import com.corpgovernment.api.travelstandard.vo.FlightTravelStandardSoaVo;
import com.corpgovernment.api.travelstandard.vo.LowPriceDomAirTicket;
import com.corpgovernment.api.travelstandard.vo.MbTravelstandFlightCabinVo;
import com.corpgovernment.api.travelstandard.vo.MbTravelstandFlightTimeVo;
import com.corpgovernment.api.travelstandard.vo.MbTravelstandFlightVo;
import com.corpgovernment.api.travelstandard.vo.MbTravelstandReasonCodeVo;
import com.corpgovernment.api.travelstandard.vo.MileageControl;
import com.corpgovernment.api.travelstandard.vo.Node;
import com.corpgovernment.api.travelstandard.vo.ProtocolPriceControl;
import com.corpgovernment.api.travelstandard.vo.RCListVo;
import com.corpgovernment.api.travelstandard.vo.TimeControl;
import com.corpgovernment.api.travelstandard.vo.TravelStandardPostVo;
import com.corpgovernment.api.travelstandard.vo.operate.FlightOperateLogVo;
import com.corpgovernment.api.travelstandard.vo.request.TravelStandardOverFlow2Request;
import com.corpgovernment.api.travelstandard.vo.response.FlightTravelStandardShowTextResponse;
import com.corpgovernment.client.ManagementClientUtil;
import com.corpgovernment.common.base.JSONResult;
import com.corpgovernment.common.base.Page;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.currency.CurrencyConversionUtil;
import com.corpgovernment.common.currency.bo.CurrencyExchangeBO;
import com.corpgovernment.common.utils.DateUtil;
import com.corpgovernment.common.utils.ListUtils;
import com.corpgovernment.common.utils.ObjectUtils;
import com.corpgovernment.common.utils.PageUtils;
import com.corpgovernment.constants.TravelStandardOwnerTypeEnum;
import com.corpgovernment.dto.travelstandard.request.GetTravelStandardByTokenRequest;
import com.corpgovernment.dto.travelstandard.response.TravelStandardResponse;
import com.corpgovernment.dto.travelstandard.response.TravelStandardRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.AdvanceRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.AmountRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.ClassDiscountRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.ClazzVo;
import com.corpgovernment.dto.travelstandard.response.rule.DistanceRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.ForbidTimeRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.LowPriceRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.PriceRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.ProtocolPriceRuleVO;
import com.corpgovernment.dto.travelstandard.response.rule.ReserveRuleVO;
import com.corpgovernment.organization.constant.CommonConst;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.organization.dataloader.ApplyTripClientLoader;
import com.corpgovernment.organization.service.IPostService;
import com.corpgovernment.supplier.constant.CommonConstant;
import com.corpgovernment.travelstandard.entity.db.MbTravelstandFlight;
import com.corpgovernment.travelstandard.entity.db.TravelStandardPost;
import com.corpgovernment.travelstandard.enums.TravelUnLimitedTypeEnum;
import com.corpgovernment.travelstandard.mapper.MbTravelstandFlightMapper;
import com.corpgovernment.travelstandard.utils.BeanConverUtil;
import com.ctrip.corp.obt.generic.exception.CommonException;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.ctrip.corp.obt.shard.context.PageContext;

import cn.hutool.core.text.StrBuilder;
import lombok.extern.slf4j.Slf4j;



@Service
@Slf4j
public class MbTravelstandFlightService extends TravelStandardBaseService implements IMbTravelstandFlightService {

    /**
     * 低价差标超标提文案
     */
    private final static String LOW_PRICE_DOM_AIR_TICKET_PROMPT = "需订%s-%s时间段内出发时间前后%s分钟内最低价";

	private final static String[] FLIGHT_RC_TEMPS = {"flightRcFcTemp", "flightRcFlTemp", "flightRcFmTemp",
            "flightRcFaTemp", "flightRcFtTemp", "flightRcAmTemp", "flightRcFpTemp"};

    private final static String[] WEEK = {"每天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};

    private final static String CLASS_FLIGHT_DURATION_NUM_DESC = "根据贵司差旅政策，飞行时长小于%s小时不可订%s";
    /**
     * 默认币种符号为人民币
     */
    private static final String CNY_CODE = "CNY";

    /**
     * 人民币符号
     */
    private static final Character CNY_SYMBOL = '¥';

    private final static String DISABLE_CONTROL = "N";

    @Autowired
    private MbTravelstandFlightMapper mbTravelstandFlightMapper;
    @Autowired
    private MbTravelstandReasonCodeService travelstandReasonCodeService;
    @Autowired
    private TravelStandardPostService travelStandardPostService;
    @Autowired
    private IPostService postService;
    @Autowired
    private TravelStandardPostService standPostService;
    @Autowired
    private MbTravelstandFlightTimeService travelstandFlightTimeService;
    @Autowired
    private ApplyTripClientLoader applyTripClientLoader;
    @Autowired
    private MbTravelstandFlightCabinService standFlightCabinService;
    @Autowired
    private MbTravelstandCurrencyExchangeService mbTravelstandCurrencyExchangeService;
    @Autowired
    private ManagementClientUtil managementClientUtil;
    @Autowired
    private TravelStandardTokenService travelStandardTokenService;

    @Override
    public void insert(MbTravelstandFlightVo model) {
        mbTravelstandFlightMapper.insert(ObjectUtils.copyProperties(model, MbTravelstandFlight.class));
    }

    @Override
    public int delete(Long id) {
        return mbTravelstandFlightMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int update(MbTravelstandFlightVo model) {
        return mbTravelstandFlightMapper.updateByPrimaryKeySelective(ObjectUtils.copyProperties(model, MbTravelstandFlight.class));
    }

    @Override
    public MbTravelstandFlightVo get(Long id) {
        return ObjectUtils.copyProperties(mbTravelstandFlightMapper.selectByPrimaryKey(id), MbTravelstandFlightVo.class);
    }

    @Override
    public Page page(MbTravelstandFlightVo model) {
        MbTravelstandFlight param = ObjectUtils.copyProperties(model, MbTravelstandFlight.class);
        PageContext.startPage(model.getPageNum(), model.getPageSize());
        List<MbTravelstandFlight> list = mbTravelstandFlightMapper.list(param);
        return PageUtils.optPageBy(list, MbTravelstandFlightVo.class);
    }

    @Transactional(rollbackFor = Exception.class)
    public void insertFlightTravelStandard(MbTravelstandFlightVo model) {
        MbTravelstandFlight travelstandFlight = ObjectUtils.copyProperties(model, MbTravelstandFlight.class);
        travelstandFlight.setDatachangeCreatetime(new Date());
        travelstandFlight.setDatachangeLasttime(new Date());
        mbTravelstandFlightMapper.insert(travelstandFlight);
        model.setId(travelstandFlight.getId());
        //从apollo获取默认RC并插入
        insertTravelstandReasonCode(FLIGHT_RC_TEMPS, model.getId());
        //插入默认时间管控
        travelstandFlightTimeService.insert(
                new MbTravelstandFlightTimeVo()
                        .setTsFlightId(model.getId())
                        .setStartTime(DateUtil.stringToDate("00:00", DateUtil.DF_HM))
                        .setEndTime(DateUtil.stringToDate("23:59", DateUtil.DF_HM))
                        .setWeek(1)
        );
        insertOperateLog(coverMbTravelstandFlightVoToFlightOperateLogVo(model));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateFlightTravelStandardProperty(FlightTravelStandardManageVo travelStandardManageVo) {
        String jobScopeId = travelStandardManageVo.getJobScopeId();
        String id = travelStandardManageVo.getId();
        if (StringUtils.isBlank(id)) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_ID_IS_NULL);
        }
        if (StringUtils.isBlank(jobScopeId)) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.JOB_SCOPEID_IS_NULL);
        }
        String orgId = travelStandardManageVo.getOrgId();
        if (StringUtils.isBlank(orgId)) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.ORG_ID_NULL);
        }
        ClassDiscountControl classDiscountControl = travelStandardManageVo.getClassDiscountControl();
        if (classDiscountControl == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.CLASS_DISCOUNT_CONTROL_IS_NULL);
        }
        LowPriceDomAirTicket lowPriceDomAirTicket = travelStandardManageVo.getLowPriceDomAirTicket();
        if (lowPriceDomAirTicket == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.LOW_PRICE_DOMAIR_TICKET_IS_NULL);
        }
        MileageControl mileageControl = travelStandardManageVo.getMileageControl();
        if (mileageControl == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.MILEAGE_CONTROL_IS_NULL);
        }
        AdvancedBook advancedBook = travelStandardManageVo.getAdvancedBook();
        if (advancedBook == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.ADVANCED_BOOK_IS_NULL);
        }
        FlightAmountControlVo amountControlVo = travelStandardManageVo.getAmountControlVo();
        if (amountControlVo == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.AMOUNT_CONTROL_IS_NULL);
        }
        TimeControl timeControl = travelStandardManageVo.getTimeControl();
        if (timeControl == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TIME_CONTROL_IS_NULL);
        }
        // 协议价
        ProtocolPriceControl protocolPrice = travelStandardManageVo.getProtocolPriceControl();
        if (Objects.isNull(protocolPrice)){
            throw new CorpBusinessException(OrganizationResponseCodeEnum.PROTOCOL_PRICE_IS_NULL);
        }
        MbTravelstandFlightVo oriTravelstandFlightVo = get(Long.valueOf(id));
        if (oriTravelstandFlightVo == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_IS_NULL);
        }
        FlightOperateLogVo oriFlightOperateLogVo = coverMbTravelstandFlightVoToFlightOperateLogVo(oriTravelstandFlightVo);
        //可选舱位
        StringBuilder classClass = new StringBuilder("");
        // 可订舱等
        List<ClassSpace.ClassCheckNew> classCheckNewList = classDiscountControl.getClassSpace().getClassCheckNewList();
        // 屏蔽舱等
        List<String> ClassShieldedList = classDiscountControl.getClassSpace().getClassShieldedList();
        if(CollectionUtils.isNotEmpty(ClassShieldedList) && CollectionUtils.isNotEmpty(classCheckNewList)) {
            for(ClassSpace.ClassCheckNew classNode : classCheckNewList) {
                for(String ClassShielded :ClassShieldedList){
                    if(StringUtils.endsWithIgnoreCase(classNode.getClassCode(), ClassShielded)) {
                        throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_CLASS_REPEAT);
                    }
                }
            }
        }
        if(CollectionUtils.isNotEmpty(classCheckNewList)) {
            // 新舱等配置
            for (ClassSpace.ClassCheckNew classNode : classCheckNewList) {
                classClass = new StringBuilder(classNode.getClassCode());
            }
        } else if(CollectionUtils.isNotEmpty(classDiscountControl.getClassSpace().getClassCheckList())) {
            // 原舱等配置
            List<Node> classNodes = classDiscountControl.getClassSpace().getClassCheckList();
            for (Node classNode : classNodes) {
                if (classNode.getIsChecked()) {
                    classClass.append(classNode.getCode());
                }
            }
        }

        //低价国内机票RC检测时间段
        Integer lowpriceTimeOption = null;
        if (StringUtils.isNotBlank(lowPriceDomAirTicket.getLowPriceDomAirTicketTimeOptionsHour()) && StringUtils.isNotBlank(lowPriceDomAirTicket.getLowPriceDomAirTicketTimeOptionsMinutes())) {
            lowpriceTimeOption = Integer.parseInt(lowPriceDomAirTicket.getLowPriceDomAirTicketTimeOptionsHour()) * 60 + Integer.parseInt(lowPriceDomAirTicket.getLowPriceDomAirTicketTimeOptionsMinutes());
        }
        // 机场比价赋默认值
        if (!CommonConst.TRUE.equals(lowPriceDomAirTicket.getAirportComparePrice())){
            lowPriceDomAirTicket.setAirportComparePrice(CommonConst.FALSE);
        }
        // 低价管控中转是否参与比价赋默认值
        if (!CommonConst.TRUE.equals(lowPriceDomAirTicket.getTransferNeedComparePrice())){
            lowPriceDomAirTicket.setTransferNeedComparePrice(CommonConst.FALSE);
        }
        // 低价浮动类型 A-固定金额浮动 B-固定比例浮动
        if (!FlightSwitchEnum.LowPriceFloatTypeSwitch.B.getCode().equals(lowPriceDomAirTicket.getLowPriceFloatType())) {
            lowPriceDomAirTicket.setLowPriceFloatType(FlightSwitchEnum.LowPriceFloatTypeSwitch.A.getCode());
        }
        // 低价浮动金额数
        Integer lowPriceFloatAmount = null;
        if(StringUtils.isNotBlank(lowPriceDomAirTicket.getLowPriceFloatAmount())) {
            lowPriceFloatAmount = Integer.parseInt(lowPriceDomAirTicket.getLowPriceFloatAmount());
        }
        // 低价浮动比例数
        Integer lowPriceFloatNum = null;
        if(StringUtils.isNotBlank(lowPriceDomAirTicket.getLowPriceFloatNum())) {
            lowPriceFloatNum = Integer.parseInt(lowPriceDomAirTicket.getLowPriceFloatNum());
        }

        MbTravelstandFlightVo travelstandFlightVo = new MbTravelstandFlightVo(
                Long.valueOf(id),
                orgId,
                travelStandardManageVo.getTitle(),
                classDiscountControl.getClassDiscountChoose(),
                classClass.toString(),
                classDiscountControl.getDiscount().getDiscountCheck(),
                new BigDecimal(classDiscountControl.getDiscount().getDiscountNum()),
                classDiscountControl.getClassDiscountRcSet(),
                lowPriceDomAirTicket.getStatus(),
                lowpriceTimeOption,
                DateUtil.stringToDate(lowPriceDomAirTicket.getLowPriceTimeStart(), DateUtil.DF_HM),
                DateUtil.stringToDate(lowPriceDomAirTicket.getLowPriceTimeEnd(), DateUtil.DF_HM),
                lowPriceDomAirTicket.getLowPriceRcSet(),
                mileageControl.getStatus(),
                mileageControl.getMileageNumber(),
                mileageControl.getMileageRcSet(),
                advancedBook.getStatus(),
                advancedBook.getAdvancedBookDays(),
                advancedBook.getBookRcSet(),
                timeControl.getStatus(),
                timeControl.getTimeChooseType(),
                timeControl.getTimeRcSet()
        );
        travelstandFlightVo.setAmountControlSwitch(amountControlVo.getStatus());
        travelstandFlightVo.setAmountControlNum(amountControlVo.getAmountControlNum());
        travelstandFlightVo.setAmountControlType(amountControlVo.getAmountRcSet());
        travelstandFlightVo.setLowpriceTransferNeedCompare(lowPriceDomAirTicket.getTransferNeedComparePrice());
        travelstandFlightVo.setProtocolPriceSwitch(protocolPrice.getStatus());
        travelstandFlightVo.setProtocolPriceControlType(protocolPrice.getProtocolPriceRcSet());
        travelstandFlightVo.setLowpriceFloatType(lowPriceDomAirTicket.getLowPriceFloatType());
        travelstandFlightVo.setLowpriceFloatAmount(lowPriceFloatAmount);
        travelstandFlightVo.setLowpriceFloatNum(lowPriceFloatNum);
        travelstandFlightVo.setAirportComparePrice(lowPriceDomAirTicket.getAirportComparePrice());
        travelstandFlightVo.setProductSwitch(travelStandardManageVo.getProductSwitch());
        log.info("需要更新的差标属性为:{}", JsonUtils.toJsonString(travelstandFlightVo));
        //更新差标属性
        if (update(travelstandFlightVo) != 1) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.CLASS_DISCOUNT_CONTROL_UPDATE_FAILED);
        }
        //更新舱等/折扣RC
        RCListVo rcListVoFc = new RCListVo();
        rcListVoFc.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFc.setRcList(classDiscountControl.getClassDiscountRcList());
        rcListVoFc.setRcType(ReasonCodeTypeEnum.FC.getCode());
        rcListVoFc.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFc);
        //更新低价RC
        RCListVo rcListVoFl = new RCListVo();
        rcListVoFl.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFl.setRcList(lowPriceDomAirTicket.getLowPriceRcCheckList());
        rcListVoFl.setRcType(ReasonCodeTypeEnum.FL.getCode());
        rcListVoFl.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFl);
        //更新公里数RC
        RCListVo rcListVoFm = new RCListVo();
        rcListVoFm.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFm.setRcList(mileageControl.getMileageRcCheckList());
        rcListVoFm.setRcType(ReasonCodeTypeEnum.FM.getCode());
        rcListVoFm.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFm);
        //更新提前预订RC
        RCListVo rcListVoFa = new RCListVo();
        rcListVoFa.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFa.setRcList(advancedBook.getBookRcCheckList());
        rcListVoFa.setRcType(ReasonCodeTypeEnum.FA.getCode());
        rcListVoFa.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFa);
        //更新金额管控RC
        RCListVo rcListVoFcp = new RCListVo();
        rcListVoFcp.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFcp.setRcList(amountControlVo.getAmountRcCheckList());
        rcListVoFcp.setRcType(ReasonCodeTypeEnum.AM.getCode());
        rcListVoFcp.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFcp);
        //更新时间RC
        RCListVo rcListVoFt = new RCListVo();
        rcListVoFt.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFt.setRcList(timeControl.getTimeRcCheckList());
        rcListVoFt.setRcType(ReasonCodeTypeEnum.FT.getCode());
        rcListVoFt.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFt);
        //更新协议价RC
        RCListVo rcListVoFp = new RCListVo();
        List<Node> rcCheckList = protocolPrice.getProtocolPriceRcCheckList();
        if (CollectionUtils.isEmpty(rcCheckList)){
            Node node = new Node();
            node.setName("protocolPrice");
            node.setIsChecked(false);
            node.setCode("test");
            rcCheckList.add(node);
        }
        rcListVoFp.setId(String.valueOf(travelstandFlightVo.getId()));
        rcListVoFp.setRcList(rcCheckList);
        rcListVoFp.setRcType(ReasonCodeTypeEnum.FP.getCode());
        rcListVoFp.setTsType(TravelStandardTypeEnum.Flight.getCode());
        travelstandReasonCodeService.updateTravelstandReasonCode(rcListVoFp);

        // MARK: 2019/12/19 此处可能产生性能瓶颈，可优化
        //删除时间信息
        travelstandFlightTimeService.deleteByTsId(travelstandFlightVo.getId());
        //循环添加地区时间信息
        List<MbTravelstandFlightTimeVo> travelstandFlightTimeVos = timeControl.getMbTravelstandFlightTimeVos();
        for (MbTravelstandFlightTimeVo travelstandFlightTimeVo : travelstandFlightTimeVos) {
            travelstandFlightTimeService.insert(travelstandFlightTimeVo);
        }

        // 新舱等配置 批量删除旧的配置 批量新增新的配置
        standFlightCabinService.deleteByTsId(travelstandFlightVo.getId(), TravelStandardTypeEnum.Flight.getCode());
        List<MbTravelstandFlightCabinVo> model = new ArrayList<>();
        // 可订舱等
        if(CollectionUtils.isNotEmpty(classCheckNewList)) {
            for(ClassSpace.ClassCheckNew classCheckNewNode: classCheckNewList) {
                MbTravelstandFlightCabinVo flightCabinVo = new MbTravelstandFlightCabinVo();
                flightCabinVo.setTsType(TravelStandardTypeEnum.Flight.getCode());
                flightCabinVo.setTsFlightId(travelstandFlightVo.getId());
                flightCabinVo.setCabinType(CommonConstant.T);
                flightCabinVo.setClassCode(classCheckNewNode.getClassCode());
                flightCabinVo.setFlightDurationType(Optional.ofNullable(classCheckNewNode.getDurationType())
                        .orElse(CommonConstant.F));
                flightCabinVo.setFlightDurationNum(classCheckNewNode.getDurationNum());
                model.add(flightCabinVo);
            }
        }
        // 屏蔽舱等
        if(CollectionUtils.isNotEmpty(ClassShieldedList)) {
            for(String classShielded : ClassShieldedList) {
                MbTravelstandFlightCabinVo flightCabinVo = new MbTravelstandFlightCabinVo();
                flightCabinVo.setTsType(TravelStandardTypeEnum.Flight.getCode());
                flightCabinVo.setTsFlightId(travelstandFlightVo.getId());
                flightCabinVo.setCabinType(CommonConstant.F);
                flightCabinVo.setClassCode(classShielded);
                flightCabinVo.setFlightDurationType(CommonConstant.F);
                model.add(flightCabinVo);
            }
        }
        if(CollectionUtils.isNotEmpty(model)) {
            standFlightCabinService.insertList(model);
        }

        //删除旧职位
        travelStandardPostService.deleteByTsidAndTsType(travelstandFlightVo.getId(), TravelStandardTypeEnum.Flight.getCode());
        //循环添加职位
        String[] jobIds = jobScopeId.split(",");
        for (String jobId : jobIds) {
            TravelStandardPostVo travelStandardPostVo = new TravelStandardPostVo();
            travelStandardPostVo.setPostid(Long.valueOf(jobId));
            travelStandardPostVo.setOrgid(orgId);
            travelStandardPostVo.setTsid(travelstandFlightVo.getId());
            travelStandardPostVo.setTstype(TravelStandardTypeEnum.Flight.getCode());
            travelStandardPostVo.setTsname(travelstandFlightVo.getName());
            travelStandardPostService.insert(travelStandardPostVo);
        }
        updateOperateLog(
                oriFlightOperateLogVo,
                coverMbTravelstandFlightVoToFlightOperateLogVo(travelstandFlightVo)
        );
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteFlightTravelStandard(Long id) {
        MbTravelstandFlightVo oriMbTravelstandFlightVo = get(id);
        if (oriMbTravelstandFlightVo == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_IS_NULL);
        }
        FlightOperateLogVo oriFlightOperateLogVo = coverMbTravelstandFlightVoToFlightOperateLogVo(oriMbTravelstandFlightVo);
        //删除机票差标
        mbTravelstandFlightMapper.deleteByPrimaryKey(id);
        //删除差标相关职位
        travelStandardPostService.deleteByTsidAndTsType(id, TravelStandardTypeEnum.Flight.getCode());
        //删除差标相关RC
        travelstandReasonCodeService.deleteByTsIdAndTsType(id, TravelStandardTypeEnum.Flight.getCode());
        //删除差标相关时间信息
        travelstandFlightTimeService.deleteByTsId(id);
        //删除差标相关舱位信息
        standFlightCabinService.deleteByTsId(id, TravelStandardTypeEnum.Flight.getCode());
        deleteOperateLog(oriFlightOperateLogVo, new FlightOperateLogVo());
    }

    public void updateStandardName(Long id, String title) {
        MbTravelstandFlightVo oriMbTravelstandFlightVo = get(id);
        if (oriMbTravelstandFlightVo == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_IS_NULL);
        }
        FlightOperateLogVo oriFlightOperateLogVo = coverMbTravelstandFlightVoToFlightOperateLogVo(oriMbTravelstandFlightVo);
        update(new MbTravelstandFlightVo() {{
            setId(Long.valueOf(id));
            setName(title);
        }});
        FlightOperateLogVo flightOperateLogVo = ObjectUtils.copyProperties(oriFlightOperateLogVo, FlightOperateLogVo.class);
        flightOperateLogVo.setName(title);
        updateOperateLog(oriFlightOperateLogVo, flightOperateLogVo);

    }

    public List<FlightTravelStandardManageVo> listFlightTravelStandard(MbTravelstandFlightVo model) {
        List<FlightTravelStandardManageVo> travelStandardManageVos = new ArrayList<>();
        List<MbTravelstandFlightVo> travelstandFlightVos = ListUtils.copyList(mbTravelstandFlightMapper.list(ObjectUtils.copyProperties(model, MbTravelstandFlight.class)), MbTravelstandFlightVo.class);
        log.info("查询的机票差标为:{}", JsonUtils.toJsonString(travelstandFlightVos));
        for (MbTravelstandFlightVo travelstandFlightVo : travelstandFlightVos) {
            //获得差标关联的岗位
            List<TravelStandardPost> travelStandardPosts = travelStandardPostService.list(new TravelStandardPostVo() {{
                setTsid(travelstandFlightVo.getId());
                setTstype(TravelStandardTypeEnum.Flight.getCode());
            }});
            //获得差标关联的RC
            List<MbTravelstandReasonCodeVo> travelstandReasonCodeVos = travelstandReasonCodeService.list(new MbTravelstandReasonCodeVo() {{
                setTsId(travelstandFlightVo.getId());
                setTsType(TravelStandardTypeEnum.Flight.getCode());
            }});
            //获得差标关联的时间管控信息
            List<MbTravelstandFlightTimeVo> mbTravelstandFlightTimeVos = travelstandFlightTimeService.list(new MbTravelstandFlightTimeVo().setTsFlightId(travelstandFlightVo.getId()));

            List<MbTravelstandFlightCabinVo> standFlightCabinVos = standFlightCabinService.list(
                    new MbTravelstandFlightCabinVo().setTsFlightId(travelstandFlightVo.getId()).setTsType(TravelStandardTypeEnum.Flight.getCode()));

            travelStandardManageVos.add(BeanConverUtil.travelstandFlightVoToFlightTravelStandardManageVo(
                    travelstandFlightVo,
                    ListUtils.copyList(travelStandardPosts, TravelStandardPostVo.class),
                    travelstandReasonCodeVos,
                    mbTravelstandFlightTimeVos,
                    standFlightCabinVos
            ));
        }
        return travelStandardManageVos;
    }

    /**
     * APP端机票差标展示
     */
    public JSONResult<FlightTravelStandardShowVo> flightTravelStandardShow(String orgId, String uid, Long postId, Long trafficId, String token) {
        if(StringUtils.isNotBlank(token)){
            return flightTravelStandardShowByToken(token);
        }

        List<FlightTravelStandardShowVo.PolicyRuleVo.PolicyDetail> policyDetails = new ArrayList<>();

        // 查询出差申请单中填写的差标
        QueryApplyTripStandardResponse flightApplyTripStandard = applyTripClientLoader.getFlightApplyTripStandard(trafficId);
        if (flightApplyTripStandard == null) {
            throw new CommonException(OrganizationResponseCodeEnum.TRAVEL_STAND_APPLY_IS_NULL);
        }
        if (BooleanUtils.isTrue(flightApplyTripStandard.getEnable())) {
            // 出差申请单差标优先
            policyDetails = buildFlightTravelStandardShowByApply(flightApplyTripStandard);
            return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
        }

        MbTravelstandFlightVo travelstandFlightVo = getMbTravelstandFlightVoByuidAndOrgId(uid, orgId, postId);

        if (Objects.nonNull(travelstandFlightVo) && DISABLE_CONTROL.equals(travelstandFlightVo.getProductSwitch())){
            policyDetails.add(buildAllControlTravelPolicyDetail("产线控制"));
            return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
        }

        if (travelstandFlightVo == null) {
            policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
            policyDetails.add(buildNoControlTravelPolicyDetail("最低价控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
            policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
        } else {
            //判断折扣/舱等，填充折扣数据
            if (FlightSwitchEnum.ClassDiscountSwitch.C.getCode().equals(travelstandFlightVo.getClassDiscountSwitch())) {
                StringBuilder content = new StringBuilder();
                List<MbTravelstandFlightCabinVo> standFlightCabinVos = standFlightCabinService.list(
                        new MbTravelstandFlightCabinVo().setTsFlightId(travelstandFlightVo.getId())
                                .setTsType(TravelStandardTypeEnum.Flight.getCode()));
                if(CollectionUtils.isNotEmpty(standFlightCabinVos)) {
                    for (MbTravelstandFlightCabinVo standFlightCabinVo : standFlightCabinVos) {
                        if(StringUtils.endsWithIgnoreCase(CommonConstant.T, standFlightCabinVo.getCabinType())) {
                            content.append(ClazzEnum.getEnumByCode(standFlightCabinVo.getClassCode())
                                    .getName());
                            if(StringUtils.endsWithIgnoreCase(CommonConstant.T, standFlightCabinVo.getFlightDurationType())) {
                                content.append("（飞行").append(standFlightCabinVo.getFlightDurationNum()).append("小时以上可订）");
                            }
                            content.append("、");
                        }
                    }
                } else if(StringUtils.isNotBlank(travelstandFlightVo.getClassClass())) {
                    List<ClazzEnum> clazzEnums = ClazzEnum.getLowerClazzEnumThanCode(travelstandFlightVo.getClassClass());
                    for (ClazzEnum clazzEnum : clazzEnums) {
                        content.append(clazzEnum.getName()).append("、");
                    }
                }
                if (content.length() > 1) {
                    content.deleteCharAt(content.length() - 1);
                }
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getClassDiscountControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("可订舱位", controlMode, content.toString()));
            }
            if (FlightSwitchEnum.ClassDiscountSwitch.D.getCode().equals(travelstandFlightVo.getClassDiscountSwitch())) {
                StringBuilder content = new StringBuilder();
                ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(travelstandFlightVo.getDiscountClass());
                content.append(clazzEnum == null ? null : clazzEnum.getName());
                content.append(travelstandFlightVo.getDiscountNum() == null ? null : travelstandFlightVo.getDiscountNum().setScale(1, RoundingMode.HALF_UP));
                content.append("折及以下");
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getClassDiscountControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("折扣控制", controlMode, content.toString()));
            }
            if (FlightSwitchEnum.ClassDiscountSwitch.N.getCode().equals(travelstandFlightVo.getClassDiscountSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
                policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
            }
            //判断低价管控，填充折扣数据
            if (FlightSwitchEnum.LowpriceSwitch.E.getCode().equals(travelstandFlightVo.getLowpriceSwitch())) {
                String content = "需订" +
                        DateUtil.dateToString(travelstandFlightVo.getLowpriceCompareTimeStart(), DateUtil.DF_HM) +
                        "-" +
                        DateUtil.dateToString(travelstandFlightVo.getLowpriceCompareTimeEnd(), DateUtil.DF_HM) +
                        "时间段内出发时间前后" +
                        travelstandFlightVo.getLowpriceTimeOption() +
                        "分钟内最低价";
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getLowpriceControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("最低价控制",controlMode,content));
            }
            if (FlightSwitchEnum.LowpriceSwitch.N.getCode().equals(travelstandFlightVo.getLowpriceSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("低价控制"));
            }
            //判断提前管控
            if (FlightSwitchEnum.AdvancedbookSwitch.E.getCode().equals(travelstandFlightVo.getAdvancedbookSwitch())) {
                String content = "提前" + travelstandFlightVo.getAdvancedbookAdvancedDayNum() + "天预定";
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getAdvancedbookControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("提前预订",controlMode,content));
            }
            if (FlightSwitchEnum.AdvancedbookSwitch.N.getCode().equals(travelstandFlightVo.getAdvancedbookSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
            }
            //判断金额管控
            if (FlightSwitchEnum.AmountControlSwitch.E.getCode().equals(travelstandFlightVo.getAmountControlSwitch())) {
                String content = mbTravelstandCurrencyExchangeService.showFlightAmountContext(CommonConst.CNY_CODE, travelstandFlightVo.getAmountControlNum());
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getAmountControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("金额管控",controlMode,content));
            }
            if (FlightSwitchEnum.AmountControlSwitch.N.getCode().equals(travelstandFlightVo.getAmountControlSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("金额管控"));
            }
            //判断公里数管控
            if (FlightSwitchEnum.MileageSwitch.E.getCode().equals(travelstandFlightVo.getMileageSwitch())) {
                String content = travelstandFlightVo.getMileageMinMileageNumber() + "公里以上可预定机票";
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getMileageControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("公里数控制", controlMode, content));
            }
            if (FlightSwitchEnum.MileageSwitch.N.getCode().equals(travelstandFlightVo.getMileageSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
            }
            //判断时间管控
            if (FlightSwitchEnum.TimeSwitch.E.getCode().equals(travelstandFlightVo.getTimeSwitch())) {
                String split = "<br>";
                StrBuilder content = new StrBuilder();
                List<MbTravelstandFlightTimeVo> mbTravelstandFlightTimeVos = travelstandFlightTimeService.list(new MbTravelstandFlightTimeVo().setTsFlightId(travelstandFlightVo.getId()));
                for (MbTravelstandFlightTimeVo mbTravelstandFlightTimeVo : mbTravelstandFlightTimeVos) {
                    content.append(WEEK[mbTravelstandFlightTimeVo.getWeek()]);
                    content.append(" ");
                    content.append(DateUtil.dateToHM(mbTravelstandFlightTimeVo.getStartTime()));
                    content.append("-");
                    content.append(DateUtil.dateToHM(mbTravelstandFlightTimeVo.getEndTime()));
                    content.append("不可起飞");
                    content.append(split);
                }
                policyDetails.add(buildTravelPolicyDetail("时间控制", ControlTypeEnum.getEnumByCode(travelstandFlightVo.getTimeControlType()).getName(), content.toString()));
            }
            if (FlightSwitchEnum.TimeSwitch.N.getCode().equals(travelstandFlightVo.getTimeSwitch())) {
                policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
            }
            //判断协议价管控
            if (FlightSwitchEnum.ProtocolPriceSwitch.E.getCode().equals(travelstandFlightVo.getProtocolPriceSwitch())) {
                String content = FlightSwitchEnum.ProtocolPriceSwitch.getEnumByCode(travelstandFlightVo.getProtocolPriceSwitch()).getName();
                String controlMode = ControlTypeEnum.getEnumByCode(travelstandFlightVo.getProtocolPriceControlType()).getName();
                policyDetails.add(buildTravelPolicyDetail("协议价控制", controlMode, content));
            }
        }

        return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
    }

    public JSONResult<FlightTravelStandardShowVo> flightTravelStandardShowByToken(String token) {
        List<FlightTravelStandardShowVo.PolicyRuleVo.PolicyDetail> policyDetails = new ArrayList<>();
        GetTravelStandardByTokenRequest request = new GetTravelStandardByTokenRequest();
        request.setTokenList(Collections.singletonList(token));
        List<TravelStandardResponse> responseList = managementClientUtil.getTravelStandardByToken(request);
        if(CollectionUtils.isEmpty(responseList)){
            policyDetails.add(buildNoControlTravelPolicyDetail("产线控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
            policyDetails.add(buildNoControlTravelPolicyDetail("最低价控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
            policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("金额管控"));
            policyDetails.add(buildNoControlTravelPolicyDetail("协议价控制"));
            return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
        }

        // 如果是出差申请单模式
        if(responseList.get(0).getTravelStandardToken().getOwnerType() == TravelStandardOwnerTypeEnum.TRAFFIC.getCode()){
            // 出差申请单差标优先
            policyDetails = buildFlightTravelStandardShowByApply(responseList.get(0).getRuleChain().getRuleList());
            return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
        }
        if(!responseList.get(0).getRuleChain().getBookable()){
            policyDetails.add(buildAllControlTravelPolicyDetail("产线控制"));
            return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
        }
        List<TravelStandardRuleVO> ruleList = responseList.get(0).getRuleChain().getRuleList();
        if (CollectionUtils.isEmpty(ruleList)) {
            policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
            policyDetails.add(buildNoControlTravelPolicyDetail("最低价控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
            policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
            policyDetails.add(buildNoControlTravelPolicyDetail("金额管控"));
            policyDetails.add(buildNoControlTravelPolicyDetail("协议价控制"));
        } else {
            ClassDiscountRuleVO classDiscountRuleVO = (ClassDiscountRuleVO) ruleList.stream().filter(t -> "ClassDiscountRule".equals(t.getName())).findFirst().orElse(null);
            //判断折扣/舱等，填充折扣数据
            if (classDiscountRuleVO != null) {
                StringBuilder content = new StringBuilder();
                if (classDiscountRuleVO.getDiscount() == null) {
                    if (CollectionUtils.isNotEmpty(classDiscountRuleVO.getClazzInfoList())) {
                        for (ClazzVo standFlightCabinVo : classDiscountRuleVO.getClazzInfoList()) {
                            content.append(ClazzEnum.getEnumByCode(standFlightCabinVo.getFlightClass())
                                    .getName());
                            if (StringUtils.endsWithIgnoreCase(CommonConstant.T, standFlightCabinVo.getDurationType())) {
                                content.append("（飞行").append(standFlightCabinVo.getDurationNum()).append("小时以上可订）");
                            }
                            content.append("、");
                        }
                    }
                    if (content.length() > 1) {
                        content.deleteCharAt(content.length() - 1);
                    }
                    String controlMode = ControlTypeEnum.getEnumByCode(classDiscountRuleVO.getRejectTypes()[0]).getName();
                    policyDetails.add(buildTravelPolicyDetail("可订舱位", controlMode, content.toString()));
                } else if (classDiscountRuleVO.getDiscount() != null) {
                    ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(classDiscountRuleVO.getClazzInfoList().get(0).getFlightClass());
                    content.append(clazzEnum == null ? null : clazzEnum.getName());
                    content.append(classDiscountRuleVO.getDiscount() == null ? null : classDiscountRuleVO.getDiscount().setScale(1, RoundingMode.HALF_UP));
                    content.append("折及以下");
                    String controlMode = ControlTypeEnum.getEnumByCode(classDiscountRuleVO.getRejectTypes()[0]).getName();
                    policyDetails.add(buildTravelPolicyDetail("折扣控制", controlMode, content.toString()));
                }
            }else {
                policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
                policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
            }

            LowPriceRuleVO lowPriceRuleVO = (LowPriceRuleVO) ruleList.stream().filter(t -> "LowPriceRule".equals(t.getName())).findFirst().orElse(null);
            //判断低价管控，填充折扣数据
            if (lowPriceRuleVO != null) {
                String content = "需订" +
                        lowPriceRuleVO.getPriceStartTime() +
                        "-" +
                        lowPriceRuleVO.getPriceEndTime() +
                        "时间段内出发时间前后" +
                        lowPriceRuleVO.getCompareInMinutes() +
                        "分钟内最低价";
                String controlMode = ControlTypeEnum.getEnumByCode(lowPriceRuleVO.getRejectTypes()[0]).getName();
                policyDetails.add(buildTravelPolicyDetail("最低价控制",controlMode,content));
            }else {
                policyDetails.add(buildNoControlTravelPolicyDetail("低价控制"));
            }
            AdvanceRuleVO advanceRuleVO = (AdvanceRuleVO) ruleList.stream().filter(t -> "AdvanceRule".equals(t.getName())).findFirst().orElse(null);
            //判断提前管控
            if (advanceRuleVO != null) {
                String content = "提前" + advanceRuleVO.getAdvanceDays() + "天预定";
                String controlMode = ControlTypeEnum.getEnumByCode(advanceRuleVO.getRejectTypes()[0]).getName();
                policyDetails.add(buildTravelPolicyDetail("提前预订",controlMode,content));
            } else {
                policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
            }
            DistanceRuleVO distanceRuleVO = (DistanceRuleVO) ruleList.stream().filter(t -> "DistanceRule".equals(t.getName())).findFirst().orElse(null);
            //判断公里数管控
            if (distanceRuleVO != null) {
                String content = distanceRuleVO.getMinKilometer() + "公里以上可预定机票";
                String controlMode = ControlTypeEnum.getEnumByCode(distanceRuleVO.getRejectTypes()[0]).getName();
                policyDetails.add(buildTravelPolicyDetail("公里数控制", controlMode, content));
            }else {
                policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
            }
            List<ForbidTimeRuleVO> forbidTimeRuleVOList = ruleList.stream()
                    .filter(t -> "ForbidTimeRule".equals(t.getName()))
                    .map(t-> (ForbidTimeRuleVO)t)
                    .collect(Collectors.toList());
            //判断时间管控
            if (CollectionUtils.isNotEmpty(forbidTimeRuleVOList)) {
                String split = "<br>";
                StrBuilder content = new StrBuilder();
                for (ForbidTimeRuleVO mbTravelstandFlightTimeVo : forbidTimeRuleVOList) {
                    content.append(WEEK[mbTravelstandFlightTimeVo.getWeekDay()]);
                    content.append(" ");
                    content.append(mbTravelstandFlightTimeVo.getStartTime());
                    content.append("-");
                    content.append(mbTravelstandFlightTimeVo.getEndTime());
                    content.append("不可起飞");
                    content.append(split);
                }
                policyDetails.add(buildTravelPolicyDetail("时间控制", ControlTypeEnum.getEnumByCode(forbidTimeRuleVOList.get(0).getRejectTypes()[0]).getName(), content.toString()));
            }else {
                policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
            }
            AmountRuleVO amountRuleVO = (AmountRuleVO) ruleList.stream().filter(t -> "AmountRule".equals(t.getName())).findFirst().orElse(null);
            //判断金额管控
            if (amountRuleVO != null) {
                String content = showFlightAmountContext(CNY_CODE, amountRuleVO.getAmountControlNum());
                String controlMode = ControlTypeEnum.getEnumByCode(amountRuleVO.getRejectTypes()[0]).getName();
                policyDetails.add(buildTravelPolicyDetail("金额管控",controlMode,content));
            } else {
                policyDetails.add(buildNoControlTravelPolicyDetail("金额管控"));
            }

            ProtocolPriceRuleVO protocolPriceRuleVO = (ProtocolPriceRuleVO) ruleList.stream().filter(t -> "ProtocolPriceRule".equals(t.getName())).findFirst().orElse(null);
            //判断协议价管控
            if (protocolPriceRuleVO != null) {
                String content = FlightSwitchEnum.ProtocolPriceSwitch.E.getName();
                String controlMode = ControlTypeEnum.getEnumByCode(protocolPriceRuleVO.getRejectTypes()[0]).getName();
                policyDetails.add(buildTravelPolicyDetail("协议价控制", controlMode, content));
            }else {
                policyDetails.add(buildNoControlTravelPolicyDetail("协议价控制"));
            }

        }

        return JSONResult.success(buildFlightTravelStandardShowVo(policyDetails));
    }

    public String showFlightAmountContext(String currencyCode, Integer amountNum) {
        if (CNY_CODE.equals(currencyCode)) {
            return "金额管控价格上限" + CNY_SYMBOL + amountNum;
        }
        StringBuilder sb = new StringBuilder();
        sb.append("金额管控价格上限").append(currencyCode).append(" ").append(amountNum);
        CurrencyExchangeBO currencyExchangeBO = CurrencyConversionUtil.exchangeCurrency(currencyCode, CNY_CODE, new BigDecimal(amountNum));
        if (!Objects.isNull(currencyExchangeBO)) {
            sb.append("(等价人民币为").append(CNY_SYMBOL).append(currencyExchangeBO.getToCurrencyAmount().toString()).append(")");
            log.info("汇率转换前币种为{}，金额为{}，转换后未四舍五入的金额为¥{}，当前token为{}", currencyCode, amountNum,
                    currencyExchangeBO.getToCurrencyAmount().toString(), currencyExchangeBO.getExchangeToken());
        }
        return sb.toString();
    }

    /**
     * 根据出差申请单差标构建APP端机票差标展示
     */
    private List<PolicyDetail> buildFlightTravelStandardShowByApply(List<TravelStandardRuleVO> ruleList) {
        List<PolicyDetail> policyDetails = new ArrayList<>();
        PriceRuleVO priceRuleVO = (PriceRuleVO) ruleList.stream().filter(t -> "PriceRule".equals(t.getName())).findFirst().orElse(null);
        ReserveRuleVO reserveRuleVO = (ReserveRuleVO) ruleList.stream().filter(t -> "ReserveRule".equals(t.getName())).findFirst().orElse(null);
        // 可订舱位不限
        if (reserveRuleVO != null && CollectionUtils.isEmpty(reserveRuleVO.getReserves())) {
            policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
        } else {
            String content = reserveRuleVO.getReserves().entrySet().stream()
                .map(Map.Entry::getKey)
                .map(CabinFlag::valueOf)
                .map(CabinFlag::getDisplayName)
                .collect(Collectors.joining("、"));
            String controlMode = ControlTypeEnum.getEnumByCode(reserveRuleVO.getRejectTypes()[0]).getName();
            policyDetails.add(buildTravelPolicyDetail("可订舱位", controlMode, content));
        }
        policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("最低价控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
        policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
        return policyDetails;
    }

    /**
     * 根据出差申请单差标构建APP端机票差标展示
     */
    private List<PolicyDetail> buildFlightTravelStandardShowByApply(QueryApplyTripStandardResponse flightApplyTripStandard) {
        List<PolicyDetail> policyDetails = new ArrayList<>();
        // 可订舱位不限
        if (TravelUnLimitedTypeEnum.isUnLimitReserve(flightApplyTripStandard.getUnLimitedType())) {
            policyDetails.add(buildNoControlTravelPolicyDetail("可订舱位"));
        } else {
            String content = flightApplyTripStandard.getStandardReserve().getReserveTypeList().stream()
                    .map(StandardReserveTypeSyncRequest::getReserveCode)
                    .map(CabinFlag::valueOf)
                    .map(CabinFlag::getDisplayName)
                    .collect(Collectors.joining("、"));
            String controlMode = ControlTypeEnum.getEnumByCode(flightApplyTripStandard.getStandardReserve().getControlType()).getName();
            policyDetails.add(buildTravelPolicyDetail("可订舱位", controlMode, content));
        }
        policyDetails.add(buildNoControlTravelPolicyDetail("折扣控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("最低价控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("公里数控制"));
        policyDetails.add(buildNoControlTravelPolicyDetail("提前预订"));
        policyDetails.add(buildNoControlTravelPolicyDetail("金额管控"));
        policyDetails.add(buildNoControlTravelPolicyDetail("时间控制"));
        return policyDetails;
    }

    /**
     * 构建国内机票差标展示返回
     */
    private FlightTravelStandardShowVo buildFlightTravelStandardShowVo(List<PolicyDetail> policyDetails) {
        FlightTravelStandardShowVo flightTravelStandardShowVo = new FlightTravelStandardShowVo();
        FlightTravelStandardShowVo.PolicyRuleVo policyRuleVo = new FlightTravelStandardShowVo.PolicyRuleVo();
        policyRuleVo.setTitle("国内机票");
        policyRuleVo.setPolicyDetail(policyDetails);

        List<FlightTravelStandardShowVo.PolicyRuleVo> policyRuleVos = new ArrayList<>();
        policyRuleVos.add(policyRuleVo);
        flightTravelStandardShowVo.setPolicyRule(policyRuleVos);
        return flightTravelStandardShowVo;
    }

    /**
     * 构建不需要控制的差标信息
     */
    private PolicyDetail buildNoControlTravelPolicyDetail(String title) {
        return buildTravelPolicyDetail(title, "不管控", "不限");
    }

    private PolicyDetail buildAllControlTravelPolicyDetail(String title){
        return buildTravelPolicyDetail(title, "禁止预订", "禁止预订");
    }

    /**
     * 构建差标信息
     */
    private PolicyDetail buildTravelPolicyDetail(String title, String controlMode, String content) {
        PolicyDetail detail = new PolicyDetail();
        detail.setTitle(title);
        detail.setContent(content);
        detail.setControlMode(controlMode);
        return detail;
    }



    public JSONResult<FlightTravelStandardShowTextResponse> flightTravelStandardShowText(String uid, String orgId, Date startDate) {
        FlightTravelStandardShowTextResponse flightTravelStandardShowTextResponse = new FlightTravelStandardShowTextResponse();
        MbTravelstandFlightVo mbTravelstandFlightVo = getMbTravelstandFlightVoByuidAndOrgId(uid, orgId, null);
        if (mbTravelstandFlightVo == null) {
            return JSONResult.success(null);
        }
        if ("N".equals(mbTravelstandFlightVo.getProductSwitch())){
            String controlInfo = "产线管控：禁止预订";
            flightTravelStandardShowTextResponse.setControlInfos(Collections.singletonList(controlInfo));
            return JSONResult.success(flightTravelStandardShowTextResponse);
        }
        //管控信息
        List<String> controlInfos = new ArrayList<>();
        //超标原因
        List<String> controlRcInfos = new ArrayList<>();
        //设置舱等/折扣
        boolean classDiscountRcFlag = false;
        if (FlightSwitchEnum.ClassDiscountSwitch.C.getCode().equals(mbTravelstandFlightVo.getClassDiscountSwitch())) {
            List<MbTravelstandFlightCabinVo> standFlightCabinVos = standFlightCabinService.list(
                    new MbTravelstandFlightCabinVo().setTsFlightId(mbTravelstandFlightVo.getId())
                            .setTsType(TravelStandardTypeEnum.Flight.getCode())
                            .setCabinType(CommonConstant.T));
            if(CollectionUtils.isNotEmpty(standFlightCabinVos)) {
                for (MbTravelstandFlightCabinVo standFlightCabinVo : standFlightCabinVos) {
                    controlInfos.add(ClazzEnum.getEnumByCode(standFlightCabinVo.getClassCode()).getName());
                }
            } else if(StringUtils.isNotBlank(mbTravelstandFlightVo.getClassClass())) {
                List<ClazzEnum> clazzEnums = ClazzEnum.getLowerClazzEnumThanCode(mbTravelstandFlightVo.getClassClass());
                for (ClazzEnum clazzEnum : clazzEnums) {
                    controlInfos.add(clazzEnum.getName());
                }
            }
            classDiscountRcFlag = true;
        }
        if (FlightSwitchEnum.ClassDiscountSwitch.D.getCode().equals(mbTravelstandFlightVo.getClassDiscountSwitch())) {
            ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(mbTravelstandFlightVo.getDiscountClass());
            controlInfos.add(clazzEnum.getName() + mbTravelstandFlightVo.getDiscountNum().setScale(1, RoundingMode.HALF_UP).toString() + "折");
            classDiscountRcFlag = true;
        }
        if (classDiscountRcFlag) {
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getClassDiscountControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.FC.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        //设置低价
        if (FlightSwitchEnum.LowpriceSwitch.E.getCode().equals(mbTravelstandFlightVo.getLowpriceSwitch())) {
            controlInfos.add("最低价");
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getLowpriceControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.FL.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        //设置公里数管控
        if (FlightSwitchEnum.MileageSwitch.E.getCode().equals(mbTravelstandFlightVo.getMileageSwitch())) {
            controlInfos.add(mbTravelstandFlightVo.getMileageMinMileageNumber() + "公里以上");
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getMileageControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.FM.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        //设置提前预订
        if (FlightSwitchEnum.AdvancedbookSwitch.E.getCode().equals(mbTravelstandFlightVo.getAdvancedbookSwitch())) {
            controlInfos.add("提前" + mbTravelstandFlightVo.getAdvancedbookAdvancedDayNum() + "天");
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getAdvancedbookControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.FA.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        //金额管控
        if (FlightSwitchEnum.AmountControlSwitch.E.getCode().equals(mbTravelstandFlightVo.getAmountControlSwitch())) {
            controlInfos.add(mbTravelstandCurrencyExchangeService.showFlightAmountContext(
                    CommonConst.CNY_CODE, mbTravelstandFlightVo.getAmountControlNum()));
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getAmountControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.AM.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        //设置时间管控
        if (FlightSwitchEnum.TimeSwitch.E.getCode().equals(mbTravelstandFlightVo.getTimeSwitch())) {
            List<MbTravelstandFlightTimeVo> mbTravelstandFlightTimeVos = travelstandFlightTimeService.list(new MbTravelstandFlightTimeVo().setTsFlightId(mbTravelstandFlightVo.getId()));
            for (MbTravelstandFlightTimeVo mbTravelstandFlightTimeVo : mbTravelstandFlightTimeVos) {
                //这里是做了一个兼容，因为陈尔竹的出差申请单判断差标是否一致和张亚强的执行差标同时调用了这支接口，startDate不为null是执行差标调用，反之亦然。
                if (startDate != null) {
                    if (mbTravelstandFlightTimeVo.getWeek() == 0 || DateUtil.getWeekDay("星期", startDate).equals(WEEK[mbTravelstandFlightTimeVo.getWeek()])) {
                        if (DateUtil.compareHourAndMinute(startDate, mbTravelstandFlightTimeVo.getStartTime()) <= 0 && DateUtil.compareHourAndMinute(startDate, mbTravelstandFlightTimeVo.getEndTime()) >= 0) {
                            controlInfos.add(
                                    DateUtil.dateToHM(mbTravelstandFlightTimeVo.getStartTime()) +
                                            "--" +
                                            DateUtil.dateToHM(mbTravelstandFlightTimeVo.getEndTime()) +
                                            "不可起飞"
                            );
                        }
                    }
                } else {
                    controlInfos.add(
                            WEEK[mbTravelstandFlightTimeVo.getWeek()] +
                                    " " +
                                    DateUtil.dateToHM(mbTravelstandFlightTimeVo.getStartTime()) +
                                    "--" +
                                    DateUtil.dateToHM(mbTravelstandFlightTimeVo.getEndTime()) +
                                    "不可起飞"
                    );
                }
            }
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getTimeControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(
                        new MbTravelstandReasonCodeVo()
                                .setTsId(mbTravelstandFlightVo.getId())
                                .setTsRcType(ReasonCodeTypeEnum.FT.getCode())
                                .setIsChecked(true)
                );
                for (MbTravelstandReasonCodeVo mbTravelstandReasonCodeVo : mbTravelstandReasonCodeVos) {
                    controlRcInfos.add(mbTravelstandReasonCodeVo.getName());
                }
            }
        }
        flightTravelStandardShowTextResponse.setControlInfos(controlInfos);
        flightTravelStandardShowTextResponse.setControlRcInfos(controlRcInfos);
        return JSONResult.success(flightTravelStandardShowTextResponse);
    }

    public JSONResult<List<String>> flightTravelStandardOverflow2(TravelStandardOverFlow2Request travelStandardOverFlow2Request) {
        List<String> rcCodes = travelStandardOverFlow2Request.getList();
        String tsId = travelStandardOverFlow2Request.getId();
        String token = travelStandardOverFlow2Request.getToken();

        if (StringUtils.isBlank(token) && (StringUtils.isBlank(tsId) && travelStandardOverFlow2Request.getTrafficId() == null)) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.PARAMS_NULL);
        }
        QueryApplyTripStandardResponse flightApplyTripStandard = null;
        if (StringUtils.isNotBlank(token)){
            flightApplyTripStandard = travelStandardTokenService.getFlightApplyTripStandard(token);
        }
        if (flightApplyTripStandard == null && travelStandardOverFlow2Request.getTrafficId() != null){
            // 查询出差申请单中填写的差标
            flightApplyTripStandard = applyTripClientLoader.getFlightApplyTripStandard(travelStandardOverFlow2Request.getTrafficId());
            if (flightApplyTripStandard == null) {
                throw new CommonException(OrganizationResponseCodeEnum.TRAVEL_STAND_APPLY_IS_NULL);
            }
            if (BooleanUtils.isTrue(flightApplyTripStandard.getEnable())) {
                // 出差申请单差标优先
                return JSONResult.success(buildFlightTravelStandardOverflow2ByApply(rcCodes, flightApplyTripStandard));
            }
        }
        if (StringUtils.isNotBlank(token)){
            FlightTravelStandardSoaVo flightTravelStandardSoaVo = travelStandardTokenService.getTravelStandardByToken(token);
            List<String> rcReasons = generateOverStandardReason(flightTravelStandardSoaVo,rcCodes,travelStandardOverFlow2Request);
            if(CollectionUtils.isNotEmpty(rcReasons)){
                return JSONResult.success(rcReasons);
            }
        }
        MbTravelstandFlightVo travelstandFlightVo = get(Long.valueOf(tsId));
        if (travelstandFlightVo == null) {
            throw new CorpBusinessException(OrganizationResponseCodeEnum.TRAVEL_STAND_IS_NULL);
        }
        List<String> texts = new ArrayList<>();
        //填充舱等/折扣信息
        for (String rcCode : rcCodes) {
            FlightSwitchEnum.RcEnum rcEnum = FlightSwitchEnum.RcEnum.getEnumByCode(rcCode);
            switch (rcEnum) {
                //填充舱等
                case classSpace: {
                    List<MbTravelstandFlightCabinVo> standFlightCabinVos = standFlightCabinService.list(
                            new MbTravelstandFlightCabinVo().setTsFlightId(travelstandFlightVo.getId())
                                    .setTsType(TravelStandardTypeEnum.Flight.getCode())
                                    .setCabinType(CommonConstant.T)
                                    .setClassCode(travelStandardOverFlow2Request.getClazzCode()));
                    if(CollectionUtils.isNotEmpty(standFlightCabinVos) &&
                            StringUtils.isNotBlank(travelStandardOverFlow2Request.getClazzCode())) {
                        // 舱等
                        String text = String.format(CLASS_FLIGHT_DURATION_NUM_DESC,
                                standFlightCabinVos.get(0).getFlightDurationNum(),
                                ClazzEnum.getEnumByCode(travelStandardOverFlow2Request.getClazzCode()).getName());
                        texts.add(text);
                    } else if(StringUtils.isNotBlank(travelStandardOverFlow2Request.getClazzCode())) {
                        String text = String.format(FlightSwitchEnum.RcEnum.classSpace.getOverDesc(),
                                ClazzEnum.getEnumByCode(travelStandardOverFlow2Request.getClazzCode()).getName());
                        texts.add(text);
                    } else if(StringUtils.isNotBlank(travelstandFlightVo.getClassClass())){
                        StringBuilder classNames = new StringBuilder();
                        List<ClazzEnum> clazzEnums = ClazzEnum.getUpperClazzEnumThanCode(travelstandFlightVo.getClassClass());
                        for (ClazzEnum clazzEnum : clazzEnums) {
                            classNames.append(clazzEnum.getName());
                            classNames.append(",");
                        }
                        if (classNames.length() > 1) {
                            classNames.deleteCharAt(classNames.length() - 1);
                        }
                        String text = String.format(FlightSwitchEnum.RcEnum.classSpace.getOverDesc(), classNames);
                        texts.add(text);
                    }
                    break;
                }
                //填充折扣
                case discount: {
                    ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(travelstandFlightVo.getDiscountClass());
                    String discountNum = travelstandFlightVo.getDiscountNum().setScale(1, RoundingMode.HALF_UP).toString();
					String text = String.format(FlightSwitchEnum.RcEnum.discount.getOverDesc(), clazzEnum.getName(), discountNum);
                    texts.add(text);
                    break;
                }
                case lowPriceDomAirTicket: {
                    String text = String.format(
                            LOW_PRICE_DOM_AIR_TICKET_PROMPT,
                            DateUtil.dateToString(travelstandFlightVo.getLowpriceCompareTimeStart(), DateUtil.DF_HM),
                            DateUtil.dateToString(travelstandFlightVo.getLowpriceCompareTimeEnd(), DateUtil.DF_HM),
                            travelstandFlightVo.getLowpriceTimeOption()
                    );
                    texts.add(text);
                    break;
                }
                case advancedBook: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.advancedBook.getOverDesc(),
                            travelstandFlightVo.getAdvancedbookAdvancedDayNum()
                    );
                    texts.add(text);
                    break;
                }
                case amountControl: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.amountControl.getOverDesc(),
                            travelstandFlightVo.getAmountControlNum()
                    );
                    texts.add(text);
                    break;
                }
                case time: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.time.getOverDesc(),
                            travelStandardOverFlow2Request.getWeek(),
                            travelStandardOverFlow2Request.getRcTimeFrom(),
                            travelStandardOverFlow2Request.getRcTimeTo()
                    );
                    texts.add(text);
                    break;
                }
                case mileageControl: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.mileageControl.getOverDesc(),
                            travelstandFlightVo.getMileageMinMileageNumber()
                    );
                    texts.add(text);
                    break;
                }
                case product: {
                    String text = RcEnum.product.getOverDesc();
                    texts.add(text);
                    break;
                }
                case protocolPrice: {
                    String text = RcEnum.protocolPrice.getOverDesc();
                    texts.add(text);
                }
                default: {
                    break;
                }
            }
        }

        return JSONResult.success(texts);
    }

    private List<String> generateOverStandardReason(FlightTravelStandardSoaVo flightTravelStandardSoaVo, List<String> rcCodes,TravelStandardOverFlow2Request travelStandardOverFlow2Request){
        if (flightTravelStandardSoaVo == null){
            return Collections.emptyList();
        }
        List<String> texts = new ArrayList<>();
        //填充舱等/折扣信息
        for (String rcCode : rcCodes) {
            FlightSwitchEnum.RcEnum rcEnum = FlightSwitchEnum.RcEnum.getEnumByCode(rcCode);
            switch (rcEnum) {
                //填充舱等
                case classSpace: {
                    if(flightTravelStandardSoaVo.getClassDiscountVo() != null &&
                            CollectionUtils.isNotEmpty(flightTravelStandardSoaVo.getClassDiscountVo().getClassCheckList()) &&
                            StringUtils.isNotBlank(travelStandardOverFlow2Request.getClazzCode())) {
                        // 舱等
                        String text = String.format(CLASS_FLIGHT_DURATION_NUM_DESC,
                                flightTravelStandardSoaVo.getClassDiscountVo().getClassCheckList().get(0).getDurationNum(),
                                ClazzEnum.getEnumByCode(travelStandardOverFlow2Request.getClazzCode()).getName());
                        texts.add(text);
                    } else if(StringUtils.isNotBlank(travelStandardOverFlow2Request.getClazzCode())) {
                        String text = String.format(FlightSwitchEnum.RcEnum.classSpace.getOverDesc(),
                                ClazzEnum.getEnumByCode(travelStandardOverFlow2Request.getClazzCode()).getName());
                        texts.add(text);
                    } else if(StringUtils.isNotBlank(flightTravelStandardSoaVo.getClassDiscountVo().getClassCode())){
                        StringBuilder classNames = new StringBuilder();
                        List<ClazzEnum> clazzEnums = ClazzEnum.getUpperClazzEnumThanCode(flightTravelStandardSoaVo.getClassDiscountVo().getClassCode());
                        for (ClazzEnum clazzEnum : clazzEnums) {
                            classNames.append(clazzEnum.getName());
                            classNames.append(",");
                        }
                        if (classNames.length() > 1) {
                            classNames.deleteCharAt(classNames.length() - 1);
                        }
                        String text = String.format(FlightSwitchEnum.RcEnum.classSpace.getOverDesc(), classNames);
                        texts.add(text);
                    }
                    break;
                }
                //填充折扣
                case discount: {
                    ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(flightTravelStandardSoaVo.getClassDiscountVo().getClassCode());
                    String discountNum = flightTravelStandardSoaVo.getClassDiscountVo().getDiscountNum().setScale(1, RoundingMode.HALF_UP).toString();
                    String text = String.format(FlightSwitchEnum.RcEnum.discount.getOverDesc(), clazzEnum.getName(), discountNum);
                    texts.add(text);
                    break;
                }
                case lowPriceDomAirTicket: {
                    String text = String.format(
                            LOW_PRICE_DOM_AIR_TICKET_PROMPT,
                            flightTravelStandardSoaVo.getLowpriceVo().getLowpriceCompareTimeStart(),
                            flightTravelStandardSoaVo.getLowpriceVo().getLowpriceCompareTimeEnd(),
                            flightTravelStandardSoaVo.getLowpriceVo().getLowPriceDomAirTicketTimeOptionsMinutes()
                    );
                    texts.add(text);
                    break;
                }
                case advancedBook: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.advancedBook.getOverDesc(),
                            flightTravelStandardSoaVo.getAdvancedBookVo().getAdvancedBookDays()
                    );
                    texts.add(text);
                    break;
                }
                case amountControl: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.amountControl.getOverDesc(),
                            flightTravelStandardSoaVo.getAmountControlVo().getAmountControlNum()
                    );
                    texts.add(text);
                    break;
                }
                case time: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.time.getOverDesc(),
                            travelStandardOverFlow2Request.getWeek(),
                            travelStandardOverFlow2Request.getRcTimeFrom(),
                            travelStandardOverFlow2Request.getRcTimeTo()
                    );
                    texts.add(text);
                    break;
                }
                case mileageControl: {
                    String text = String.format(
                            FlightSwitchEnum.RcEnum.mileageControl.getOverDesc(),
                            flightTravelStandardSoaVo.getMileageVo().getMileageNumber()
                    );
                    texts.add(text);
                    break;
                }
                case product: {
                    String text = RcEnum.product.getOverDesc();
                    texts.add(text);
                    break;
                }
                case protocolPrice: {
                    String text = RcEnum.protocolPrice.getOverDesc();
                    texts.add(text);
                }
                default: {
                    break;
                }
            }
        }

        return texts;
    }

    /**
     * 根据出差申请单关联差标构建超标展示信息
     */
    private List<String> buildFlightTravelStandardOverflow2ByApply(List<String> rcCodes, QueryApplyTripStandardResponse flightApplyTripStandard) {
        List<String> texts = new ArrayList<>();
        // 舱等超标
        if (rcCodes.stream().map(RcEnum::getEnumByCode).collect(Collectors.toSet()).contains(RcEnum.classSpace)) {
            Set<ClazzEnum> enableClazz = flightApplyTripStandard.getStandardReserve().getReserveTypeList().stream()
                    .map(StandardReserveTypeSyncRequest::getReserveCode)
                    .map(ClazzEnum::valueOf).collect(Collectors.toSet());

            String unEnableClazz = Arrays.stream(ClazzEnum.values()).filter(clazz -> !enableClazz.contains(clazz)).map(ClazzEnum::getName).collect(Collectors.joining(","));
            texts.add(String.format(RcEnum.classSpace.getOverDesc(), unEnableClazz));
        }
        return texts;
    }

    /**
     * 根据uid和orgId获得对应机票差标
     *
     * @param uid
     * @param orgId 组织id，对应的组织类型可能是公司、部门。
     *              用于从mb_user_org_relation表中拿到对应的职级id
     * @return
     */
    public MbTravelstandFlightVo getMbTravelstandFlightVoByuidAndOrgId(String uid, String orgId, Long postId) {

        if (Objects.isNull(postId) || postId == 0) {
            if (StringUtils.isBlank(uid)) {
                throw new CorpBusinessException(OrganizationResponseCodeEnum.UID_NULL);
            }
            if (StringUtils.isBlank(orgId)) {
                throw new CorpBusinessException(OrganizationResponseCodeEnum.ORG_ID_NULL);
            }

            //根据uid和orgId查到对应职位
            PostVo postVo = postService.listPostByUidAndOrgId(uid, orgId);
            //判断岗位是否存在
            if (postVo == null) {
                return null;
            }
            postId = postVo.getId();
        }

        //根据职位查找对应机票差标
        TravelStandardPostVo vo = new TravelStandardPostVo();
        vo.setPostid(postId);
        vo.setTstype(TravelStandardTypeEnum.Flight.getCode());
        List<TravelStandardPost> travelStandardPostVos = standPostService.list(vo);
        if (travelStandardPostVos == null || travelStandardPostVos.size() == 0) {
            return null;
        }
        //获取对应差标
        return get(travelStandardPostVos.get(0).getTsid());
    }

    /**
     * 将MbTravelstandFlightVo转换为FlightOperateLogVo
     */
    private FlightOperateLogVo coverMbTravelstandFlightVoToFlightOperateLogVo(MbTravelstandFlightVo mbTravelstandFlightVo) {
        if (mbTravelstandFlightVo != null) {
            FlightOperateLogVo flightOperateLogVo = new FlightOperateLogVo();
            flightOperateLogVo.setName(mbTravelstandFlightVo.getName());
            //设置职级范围
            List<String> jobNames = travelStandardPostService.getJobNamesByTsIdAndTsType(mbTravelstandFlightVo.getId(), TravelStandardTypeEnum.Flight.getCode());
            StringBuilder jobScope = new StringBuilder();
            for (String jobName : jobNames) {
                jobScope.append(jobName);
                jobScope.append(",");
            }
            if (jobNames.size() > 0) {
                jobScope.deleteCharAt(jobScope.length() - 1);
            }
            flightOperateLogVo.setJobScope(jobScope.toString());
            //设置舱等/折扣信息
            FlightSwitchEnum.ClassDiscountSwitch classDiscountSwitch = FlightSwitchEnum.ClassDiscountSwitch.getEnumByCode(mbTravelstandFlightVo.getClassDiscountSwitch());
            flightOperateLogVo.setClassDiscountSwitch(classDiscountSwitch == null ? "" : classDiscountSwitch.getName());
            StringBuilder classDiscountInfo = new StringBuilder();
            if (FlightSwitchEnum.ClassDiscountSwitch.C.getCode().equals(mbTravelstandFlightVo.getClassDiscountSwitch())) {
                ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(mbTravelstandFlightVo.getClassClass());
                classDiscountInfo.append(clazzEnum == null ? "" : clazzEnum.getName());
            } else if (FlightSwitchEnum.ClassDiscountSwitch.D.getCode().equals(mbTravelstandFlightVo.getClassDiscountSwitch())) {
                ClazzEnum clazzEnum = ClazzEnum.getEnumByCode(mbTravelstandFlightVo.getDiscountClass());
                classDiscountInfo.append(clazzEnum == null ? "" : clazzEnum.getName());
                classDiscountInfo.append(",");
                classDiscountInfo.append(mbTravelstandFlightVo.getDiscountNum().setScale(1, RoundingMode.HALF_UP).toString());
                classDiscountInfo.append("折");
            }
            flightOperateLogVo.setClassDiscountInfo(classDiscountInfo.toString());
            //设置低价信息
            FlightSwitchEnum.LowpriceSwitch lowpriceSwitch = FlightSwitchEnum.LowpriceSwitch.getEnumByCode(mbTravelstandFlightVo.getLowpriceSwitch());
            flightOperateLogVo.setLowpriceSwitch(lowpriceSwitch == null ? null : lowpriceSwitch.getName());
            flightOperateLogVo.setLowpriceTimeOptionHour(mbTravelstandFlightVo.getLowpriceTimeOption() == null ? null : String.valueOf(mbTravelstandFlightVo.getLowpriceTimeOption() / 60));
            flightOperateLogVo.setLowpriceTimeOptionMinute(mbTravelstandFlightVo.getLowpriceTimeOption() == null ? null : String.valueOf(mbTravelstandFlightVo.getLowpriceTimeOption() % 60));
            flightOperateLogVo.setLowpriceCompareTimeStart(mbTravelstandFlightVo.getLowpriceCompareTimeStart() == null ? null : DateUtil.dateToString(mbTravelstandFlightVo.getLowpriceCompareTimeStart(), DateUtil.DF_HM));
            flightOperateLogVo.setLowpriceCompareTimeEnd(mbTravelstandFlightVo.getLowpriceCompareTimeEnd() == null ? null : DateUtil.dateToString(mbTravelstandFlightVo.getLowpriceCompareTimeEnd(), DateUtil.DF_HM));
            flightOperateLogVo.setAirportComparePrice(mbTravelstandFlightVo.getAirportComparePrice());
            flightOperateLogVo.setTransferNeedComparePrice(mbTravelstandFlightVo.getLowpriceTransferNeedCompare());
            flightOperateLogVo.setLowpriceFloatType(mbTravelstandFlightVo.getLowpriceFloatType());
            flightOperateLogVo.setLowpriceFloatAmount(mbTravelstandFlightVo.getLowpriceFloatAmount() == null ? "0" :
                    mbTravelstandFlightVo.getLowpriceFloatAmount() .toString());
            flightOperateLogVo.setLowpriceFloatNum(mbTravelstandFlightVo.getLowpriceFloatNum() == null ? "0" :
                    mbTravelstandFlightVo.getLowpriceFloatNum().toString());
            //设置协议价信息
            FlightSwitchEnum.ProtocolPriceSwitch protocolPriceSwitch = FlightSwitchEnum.ProtocolPriceSwitch.getEnumByCode(mbTravelstandFlightVo.getProtocolPriceSwitch());
            flightOperateLogVo.setProtocolPriceSwitch(Objects.isNull(protocolPriceSwitch) ? null : protocolPriceSwitch.getName());
            //舱等/折扣超标管控原因
            ControlTypeEnum classDiscountControlType = ControlTypeEnum.getEnumByCode(mbTravelstandFlightVo.getClassDiscountControlType());
            flightOperateLogVo.setClassDiscountControlType(classDiscountControlType == null ? "" : classDiscountControlType.getName());
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getClassDiscountControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(new MbTravelstandReasonCodeVo() {{
                    setTsId(mbTravelstandFlightVo.getId());
                    setTsRcType(ReasonCodeTypeEnum.FC.getCode());
                }});
                flightOperateLogVo.setClassDiscountControlRcs(appendRcs(mbTravelstandReasonCodeVos));
            }
            //低价管控原因
            ControlTypeEnum lowpriceControlType = ControlTypeEnum.getEnumByCode(mbTravelstandFlightVo.getLowpriceControlType());
            flightOperateLogVo.setLowpriceControlType(lowpriceControlType == null ? null : lowpriceControlType.getName());
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getLowpriceControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(new MbTravelstandReasonCodeVo() {{
                    setTsId(mbTravelstandFlightVo.getId());
                    setTsRcType(ReasonCodeTypeEnum.FL.getCode());
                }});
                flightOperateLogVo.setLowpriceControlRcs(appendRcs(mbTravelstandReasonCodeVos));
            }
            //协议价超标管控原因
            ControlTypeEnum protocolPriceControlType = ControlTypeEnum.getEnumByCode(mbTravelstandFlightVo.getProtocolPriceControlType());
            flightOperateLogVo.setProtocolPriceControlType(Objects.isNull(protocolPriceControlType)? null : protocolPriceControlType.getName());
            if (ControlTypeEnum.C.getCode().equals(mbTravelstandFlightVo.getProtocolPriceControlType())) {
                List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos = travelstandReasonCodeService.list(new MbTravelstandReasonCodeVo() {{
                    setTsId(mbTravelstandFlightVo.getId());
                    setTsRcType(ReasonCodeTypeEnum.FP.getCode());
                }});
                flightOperateLogVo.setProtocolPriceControlRcs(appendRcs(mbTravelstandReasonCodeVos));
            }
            return flightOperateLogVo;
        }
        return null;
    }

    private String appendRcs(List<MbTravelstandReasonCodeVo> mbTravelstandReasonCodeVos) {
        StringBuilder classDiscountControlRcs = new StringBuilder();
        for (MbTravelstandReasonCodeVo codeVo : mbTravelstandReasonCodeVos) {
            classDiscountControlRcs.append(codeVo.getName());
            classDiscountControlRcs.append(",");
        }
        if (mbTravelstandReasonCodeVos.size() > 0) {
            classDiscountControlRcs.deleteCharAt(classDiscountControlRcs.length() - 1);
        }
        return classDiscountControlRcs.toString();
    }


}
